package com.flexrrb.containers
{
	import com.iwobanas.effects.Slide;
	import com.iwobanas.effects.SlideDown;
	import com.iwobanas.effects.SlideLeft;
	import com.iwobanas.effects.SlideRight;
	import com.iwobanas.effects.SlideUp;
	
	import flash.display.DisplayObject;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import mx.containers.HBox;
	import mx.containers.VBox;
	import mx.controls.LinkButton;
	import mx.effects.Resize;
	import mx.events.ChildExistenceChangedEvent;
	import mx.events.EffectEvent;
	import mx.managers.PopUpManager;


	public class SlidingBox extends VBox
	{
		public static const OPEN_STATE:String = "open";
		public static const CLOSED_STATE:String = "closed";
		public static const ANCHOR_RIGHT:String = "right";
		public static const ANCHOR_LEFT:String = "left";
		public static const ANCHOR_TOP:String = "top";
		public static const ANCHOR_BOTTOM:String = "bottom";

		protected var _state:String;
		protected var _anchor:String;
		protected var originalWidth:int;
		protected var originalHeight:int;
		protected var openingMainBox:Boolean;
		protected var closingMainBox:Boolean;
		protected var closeAfterOpen:Boolean;


		protected var floatState:Boolean;
		protected var openingFloatBox:Boolean;
		protected var closingFloatBox:Boolean;

		protected var oneTimeAdded:Boolean;

		protected var _headerBox:HBox;
		protected var _headerSlideButton:LinkButton;
		protected var _headerSlideButtonLabel:String;
		protected var _headerSlideButtonToolTip:String;

		protected var _closedBox:VBox;
		protected var _closedSlideButton:LinkButton;
		protected var _closedSlideButtonLabel:String;
		protected var _closedSlideButtonToolTip:String;

		protected var _floatingBox:VBox;

		[Embed(source="../../../assets/left.png")]
		protected var _slideButtonLeftIcon:Class;
		[Embed(source="../../../assets/leftDark.png")]
		protected var _slideButtonLeftFocusIcon:Class;
		[Embed(source="../../../assets/right.png")]
		protected var _slideButtonRightIcon:Class;
		[Embed(source="../../../assets/rightDark.png")]
		protected var _slideButtonRightFocusIcon:Class;
		[Embed(source="../../../assets/up.png")]
		protected var _slideButtonUpIcon:Class;
		[Embed(source="../../../assets/upDark.png")]
		protected var _slideButtonUpFocusIcon:Class;
		[Embed(source="../../../assets/down.png")]
		protected var _slideButtonDownIcon:Class;
		[Embed(source="../../../assets/downDark.png")]
		protected var _slideButtonDownFocusIcon:Class;

		public function SlidingBox()
		{
			super();

			addEventListener(ChildExistenceChangedEvent.CHILD_ADD, childAddHandler, false, 0, true);

			_state = OPEN_STATE;
			_anchor = ANCHOR_LEFT;

			_floatingBox = new VBox();
			_floatingBox.id = "floatingBox";
			_floatingBox.setStyle("backgroundColor", "blue");
			_floatingBox.setStyle("verticalGap", 0);
			_floatingBox.percentHeight = 100;
			_floatingBox.percentWidth = 100;
			_headerBox = new HBox();
			_headerBox.id = "headerBox";
			_headerBox.setStyle("backgroundColor", "0xFFFF00");
			_headerBox.percentWidth = 100;
			_headerBox.height = 20;

			_headerSlideButton = new LinkButton();
			_headerSlideButton.label = _headerSlideButtonLabel;
			_headerSlideButton.width = 20;
			_headerSlideButton.height = 20;
			_headerSlideButton.toolTip = _headerSlideButtonToolTip;
			_headerSlideButton.setStyle("cornerRadius", 0);
			_headerSlideButton.addEventListener(MouseEvent.CLICK, onSlideButtonClick, false, 0, true);

			_headerBox.addChild(_headerSlideButton);
			_floatingBox.addChild(_headerBox);
		}

		private function childAddHandler(event:ChildExistenceChangedEvent):void
		{
			var child:DisplayObject = event.relatedObject;
			if (child != _floatingBox && child != _closedBox)
			{
				_floatingBox.addChild(child);
			}
		}

		protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);

			if (_state == OPEN_STATE || openingMainBox)
			{
				_floatingBox.visible = true;
				_floatingBox.includeInLayout = true;				
				_headerBox.visible = true;
				_headerBox.includeInLayout = true;
				_headerSlideButton.visible = true;
				_headerSlideButton.includeInLayout = true;
				_closedBox.visible = false;
				_closedBox.includeInLayout = false;
				switch (_anchor)
				{
					case ANCHOR_LEFT:
						_headerSlideButton.setStyle("icon", _slideButtonRightIcon);
						_headerBox.setStyle("horizontalAlign", "right");
						break;
					case ANCHOR_RIGHT:
						_headerSlideButton.setStyle("icon", _slideButtonLeftIcon);
						_headerBox.setStyle("horizontalAlign", "left");
						break;
					case ANCHOR_TOP:
						_headerSlideButton.setStyle("icon", _slideButtonUpIcon);
						_headerBox.setStyle("horizontalAlign", "left");
						break;
					case ANCHOR_BOTTOM:
						_headerSlideButton.setStyle("icon", _slideButtonDownIcon);
						_headerBox.setStyle("horizontalAlign", "left");
						break;
				}
			}
			else if (!floatState)
			{
				_floatingBox.visible = false;
				_floatingBox.includeInLayout = false;
				_closedBox.visible = true;
				_closedBox.includeInLayout = true;
				switch (_anchor)
				{
					case ANCHOR_LEFT:
						_closedSlideButton.setStyle("icon", _slideButtonLeftIcon);
						_headerBox.setStyle("horizontalAlign", "right");
						_closedBox.percentHeight = 100;
						_closedBox.width = 20;
						break;
					case ANCHOR_RIGHT:
						_closedSlideButton.setStyle("icon", _slideButtonRightIcon);
						_headerBox.setStyle("horizontalAlign", "left");
						_closedBox.percentHeight = 100;
						_closedBox.width = 20;
						break;
					case ANCHOR_TOP:
						_closedSlideButton.setStyle("icon", _slideButtonDownIcon);
						_headerBox.setStyle("horizontalAlign", "left");
						_closedBox.percentWidth = 100;
						_closedBox.height = 20;
						break;
					case ANCHOR_BOTTOM:
						_closedSlideButton.setStyle("icon", _slideButtonUpIcon);
						_headerBox.setStyle("horizontalAlign", "left");
						_closedBox.percentWidth = 100;
						_closedBox.height = 20;
						break;
				}
			}
		}

		protected override function createChildren():void
		{
			if (!oneTimeAdded)
			{
				if (_closedBox == null)
				{
					_closedBox = new VBox();
					_closedBox.id = "closedBox";
					_closedBox.setStyle("backgroundColor", "black");

					/* switch (_anchor)
					{
						case ANCHOR_LEFT:
						case ANCHOR_RIGHT:
							_closedBox.percentHeight = 100;
							_closedBox.width = 20;
							break;
						case ANCHOR_TOP:
						case ANCHOR_BOTTOM:
							_closedBox.percentWidth = 100;
							_closedBox.height = 20;
							break;
					} */

					_closedBox.addEventListener(MouseEvent.CLICK, closeBoxClickHandler, false, 0, true);

					_closedSlideButton = new LinkButton();
					_closedSlideButton.label = _closedSlideButtonLabel;
					_closedSlideButton.width = 20;
					_closedSlideButton.height = 20;
					_closedSlideButton.toolTip = _closedSlideButtonToolTip;
					_closedSlideButton.setStyle("cornerRadius", 0);
					_closedSlideButton.addEventListener(MouseEvent.CLICK, onSlideButtonClick, false, 0, true);

					_closedBox.addChild(_closedSlideButton);

					this.addChild(_closedBox);
				}

				this.addChild(_floatingBox);
				oneTimeAdded = true;
			}
			super.createChildren();
		}

		private function closeBoxClickHandler(event:MouseEvent):void
		{
			if (openingFloatBox || closingFloatBox)
				return;

			if (!floatState)
			{
				floatState = true;
				openingFloatBox = true;
				try
				{
					this.removeChild(_floatingBox);
				}
				catch (e:Error)
				{

				}

				var point:Point = new Point(0, 0);
				point = this.localToGlobal(point);
				var slide:Slide;
				switch (_anchor)
				{
					case ANCHOR_LEFT:
						slide = new SlideRight();
						slide.duration = 500;
						_floatingBox.x = point.x + _closedBox.width;
						_floatingBox.y = point.y;
						_floatingBox.height = this.height;
						_floatingBox.width = originalWidth;
						break;
					case ANCHOR_RIGHT:
						slide = new SlideLeft();
						slide.duration = 500;
						_floatingBox.x = point.x - originalWidth;
						_floatingBox.y = point.y;
						_floatingBox.height = this.height;
						_floatingBox.width = originalWidth;
						break;
					case ANCHOR_TOP:
						slide = new SlideDown();
						slide.duration = 500;
						_floatingBox.x = point.x;
						_floatingBox.y = point.y+_closedBox.height;
						_floatingBox.height = originalHeight;
						_floatingBox.width = this.width;
						_headerBox.visible = false;
						_headerBox.includeInLayout = false;
						break;
					case ANCHOR_BOTTOM:
						slide = new SlideUp();
						slide.duration = 500;
						_floatingBox.x = point.x;
						_floatingBox.y = point.y - originalHeight;
						_floatingBox.height = originalHeight;
						_floatingBox.width = this.width;
						_headerBox.visible = false;
						_headerBox.includeInLayout = false;
						break;
				}
				slide.addEventListener(EffectEvent.EFFECT_END, floatShowEnd, false, 0, true);
				slide.target = _floatingBox;				
				_floatingBox.visible = true;
				_floatingBox.includeInLayout = true;				
				_headerSlideButton.visible = false;
				_headerSlideButton.includeInLayout = false;
				PopUpManager.addPopUp(_floatingBox, this);
				this.addEventListener(MouseEvent.MOUSE_OUT, mouseOutsideHandler, false, 0, true);
				_floatingBox.addEventListener(MouseEvent.MOUSE_OUT, mouseOutsideHandler, false, 0, true);
				slide.play();
			}
			else
			{
				startHidingFloatingBox();
			}
		}

		private function mouseOutsideHandler(event:MouseEvent):void
		{
			var floatingRect:Rectangle = new Rectangle(_floatingBox.x, _floatingBox.y, _floatingBox.width, _floatingBox.height);
			var point:Point = new Point(this.x, this.y);
			point = this.localToGlobal(point);
			var slideRect:Rectangle = new Rectangle(point.x, point.y, this.width, this.height);
			if (!floatingRect.contains(event.stageX, event.stageY) && !slideRect.contains(event.stageX, event.stageY))
			{
				if (!openingFloatBox)
				{
					if (floatState)
					{
						startHidingFloatingBox();
					}
				}
				else
				{
					closeAfterOpen = true;
				}
			}
			if (openingFloatBox)
			{
				closeAfterOpen = true;
			}
		}

		private function startHidingFloatingBox():void
		{
			if (floatState)
			{
				closingFloatBox = true;
				this.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutsideHandler);
				_floatingBox.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutsideHandler);
				var slide:Slide;
				switch (_anchor)
				{
					case ANCHOR_LEFT:
						slide = new SlideLeft();
						slide.duration = 500;
						break;
					case ANCHOR_RIGHT:
						slide = new SlideRight();
						slide.duration = 500;
						break;
					case ANCHOR_TOP:
						slide = new SlideUp();
						slide.duration = 500;
						break;
					case ANCHOR_BOTTOM:
						slide = new SlideDown();
						slide.duration = 500;
						break;
				}
				slide.addEventListener(EffectEvent.EFFECT_END, floatHideEnd, false, 0, true);
				slide.target = _floatingBox;
				slide.showTarget = false;
				slide.play();
			}
		}

		private function floatShowEnd(event:EffectEvent):void
		{
			openingFloatBox = false;
			if (closeAfterOpen)
			{
				var floatingRect:Rectangle = new Rectangle(_floatingBox.x, _floatingBox.y, _floatingBox.width, _floatingBox.height);
				var point:Point = new Point(this.x, this.y);
				point = this.localToGlobal(point);
				var slideRect:Rectangle = new Rectangle(point.x, point.y, this.width, this.height);

				if (!floatingRect.contains(stage.mouseX, stage.mouseY) && !slideRect.contains(stage.mouseX, stage.mouseY))
				{
					startHidingFloatingBox();
				}
				closeAfterOpen = false;

			}
		}

		private function floatHideEnd(event:EffectEvent):void
		{
			closingFloatBox = false;
			PopUpManager.removePopUp(_floatingBox);
			floatState = false;
		}

		private function onSlideButtonClick(event:MouseEvent):void
		{
			try
			{
				this.getChildIndex(_floatingBox);
				_floatingBox.percentHeight=100;
			}
			catch (e:Error)
			{
				//_floatingBox.percentWidth = 100;
				_floatingBox.percentHeight=100;
				floatState = false;
				this.addChild(_floatingBox);
			}
			/* if (floatState)
			   {
			   //floatHideEnd(null);
			   _floatingBox.setStyle("addedEffect", "");
			   _floatingBox.percentWidth = 100;
			   this.addChild(_floatingBox);
			   floatState = false;
			 } */

			animate();
			event.stopPropagation();
		}

		private function animate():void
		{
			var effect:Resize;
			effect = new Resize();
			effect.addEventListener(EffectEvent.EFFECT_END, onMoveEnd, false, 0, true);
			effect.target = this;
			if (_state == OPEN_STATE)
			{
				closingMainBox = true;

				switch (_anchor)
				{
					case ANCHOR_LEFT:
					case ANCHOR_RIGHT:
						effect.widthFrom = originalWidth = this.width;
						effect.widthTo = _closedBox.width;
						break;
					case ANCHOR_TOP:
					case ANCHOR_BOTTOM:
						effect.heightFrom = originalHeight = this.height;
						effect.heightTo = _closedBox.height;
						break;
				}
			}
			else
			{
				openingMainBox = true;

				switch (_anchor)
				{
					case ANCHOR_LEFT:
					case ANCHOR_RIGHT:
						effect.widthFrom = this.width;
						effect.widthTo = originalWidth;
						break;
					case ANCHOR_TOP:
					case ANCHOR_BOTTOM:
						effect.heightFrom = this.height;
						effect.heightTo = originalHeight;
						break;
				}
			}
			this.verticalScrollPolicy = "off";
			this.horizontalScrollPolicy = "off";
			effect.play();
		}

		private function onMoveEnd(event:EffectEvent):void
		{
			if (_state == OPEN_STATE)
			{
				_state = CLOSED_STATE;
				closingMainBox = false;
			}
			else
			{
				_state = OPEN_STATE;
				openingMainBox = false;
			}
			this.verticalScrollPolicy = "auto";
			this.horizontalScrollPolicy = "auto";
			_floatingBox.percentHeight=100;
		}

		public function get anchor():String
		{
			return _anchor;
		}

		public function set anchor(value:String):void
		{
			_anchor = value;
			this.invalidateDisplayList();
		}
	}
}